package au.com.handsunited.jodawrapper.hibernate;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.EnhancedUserType;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import au.com.handsunited.jodawrapper.JodaLocalDateWrapper;

/**
 * @author Object
 * 
 */
public class PersistentJodaLocalDateWrapper implements EnhancedUserType,
		Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4185664613277007255L;

	public final static PersistentJodaLocalDateWrapper INSTANCE = new PersistentJodaLocalDateWrapper();

	private static Logger logger = LoggerFactory
			.getLogger(PersistentJodaLocalDateWrapper.class);

	private static final int[] SQL_TYPES = new int[] { Types.DATE, };

	/**
	 * @see org.hibernate.usertype.EnhancedUserType#fromXMLString(java.lang.String)
	 */
	@Override
	public Object fromXMLString(String xmlValue) {

		return new JodaLocalDateWrapper(new LocalDate(xmlValue));
	}

	/**
	 * @see org.hibernate.usertype.EnhancedUserType#objectToSQLString(java.lang.Object)
	 */
	@Override
	public String objectToSQLString(Object value) {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see org.hibernate.usertype.EnhancedUserType#toXMLString(java.lang.Object)
	 */
	@Override
	public String toXMLString(Object value) {
		return ((JodaLocalDateWrapper) value).getDate().toString();
	}

	/**
	 * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable,
	 *      java.lang.Object)
	 */
	@Override
	public Object assemble(Serializable cached, Object owner)
			throws HibernateException {
		return cached;
	}

	/**
	 * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
	 */
	@Override
	public Object deepCopy(Object value) throws HibernateException {

		if (value == null) {
			return null;
		}
		return new JodaLocalDateWrapper(new LocalDate(
				((JodaLocalDateWrapper) value).getDate()));
	}

	/**
	 * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
	 */
	@Override
	public Serializable disassemble(Object value) throws HibernateException {
		return (Serializable) value;
	}

	/**
	 * @see org.hibernate.usertype.UserType#equals(java.lang.Object,
	 *      java.lang.Object)
	 */
	@Override
	public boolean equals(Object x, Object y) throws HibernateException {

		if (x == y) {
			return true;
		}

		if ((x == null) || (y == null)) {
			return false;
		}

		JodaLocalDateWrapper jdtwx = (JodaLocalDateWrapper) x;
		JodaLocalDateWrapper jdtwy = (JodaLocalDateWrapper) y;

		return jdtwx.getDate().equals(jdtwy.getDate());
	}

	/**
	 * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
	 */
	@Override
	public int hashCode(Object x) throws HibernateException {
		return ((JodaLocalDateWrapper) x).getDate().hashCode();
	}

	/**
	 * @see org.hibernate.usertype.UserType#isMutable()
	 */
	@Override
	public boolean isMutable() {
		return false;
	}

	/**
	 * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,
	 *      java.lang.String[], java.lang.Object)
	 */
	@Override
	public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
			throws HibernateException, SQLException {
		return nullSafeGet(rs, names[0]);
	}

	/**
	 * 
	 * @param rs
	 * @param string
	 * @return
	 * @throws SQLException
	 */
	public Object nullSafeGet(ResultSet rs, String string) throws SQLException {
		Object timestamp = Hibernate.DATE.nullSafeGet(rs, string);

		if (timestamp == null) {
			return null;
		}

		LocalDate date = new LocalDate(timestamp);

		return new JodaLocalDateWrapper(date);
	}

	/**
	 * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,
	 *      java.lang.Object, int)
	 */
	@Override
	public void nullSafeSet(PreparedStatement st, Object value, int index)
			throws HibernateException, SQLException {

		if (value == null) {
			Hibernate.DATE.nullSafeSet(st, null, index);
		} else {
			Hibernate.DATE.nullSafeSet(st, ((JodaLocalDateWrapper) value)
					.getDate().toDateTimeAtStartOfDay().toDate(), index);
		}
	}

	/**
	 * @see org.hibernate.usertype.UserType#replace(java.lang.Object,
	 *      java.lang.Object, java.lang.Object)
	 */
	@Override
	public Object replace(Object original, Object target, Object owner)
			throws HibernateException {
		return original;
	}

	/**
	 * @see org.hibernate.usertype.UserType#returnedClass()
	 */
	@Override
	public Class returnedClass() {
		return JodaLocalDateWrapper.class;
	}

	/**
	 * @see org.hibernate.usertype.UserType#sqlTypes()
	 */
	@Override
	public int[] sqlTypes() {
		return SQL_TYPES;
	}

}
